package model

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"time"

	"wxpay/pkg/util"

	"gorm.io/datatypes"
)

/*
DB Table Details
-------------------------------------


Table: alipay_agent_sign
[ 0] id                                             INT8                 null: false  primary: true   isArray: false  auto: false  col: INT8            len: -1      default: []
[ 1] apply_no                                       VARCHAR(32)          null: false  primary: false  isArray: false  auto: false  col: VARCHAR         len: 32      default: []
[ 2] brand_id                                       VARCHAR(16)          null: false  primary: false  isArray: false  auto: false  col: VARCHAR         len: 16      default: []
[ 3] alipay_account                                 VARCHAR(32)          null: false  primary: false  isArray: false  auto: false  col: VARCHAR         len: 32      default: []
[ 4] contact_info                                   JSONB                null: false  primary: false  isArray: false  auto: false  col: JSONB           len: -1      default: []
[ 5] batch_no                                       VARCHAR(32)          null: false  primary: false  isArray: false  auto: false  col: VARCHAR         len: 32      default: []
[ 6] sign_info                                      JSONB                null: false  primary: false  isArray: false  auto: false  col: JSONB           len: -1      default: []
[ 7] sign_type                                      VARCHAR(16)          null: false  primary: false  isArray: false  auto: false  col: VARCHAR         len: 16      default: []
[ 8] apply_state                                    VARCHAR(32)          null: true   primary: false  isArray: false  auto: false  col: VARCHAR         len: 32      default: []
[ 9] apply_state_desc                               VARCHAR(64)          null: true   primary: false  isArray: false  auto: false  col: VARCHAR         len: 64      default: []
[10] audit_detail                                   JSONB                null: true   primary: false  isArray: false  auto: false  col: JSONB           len: -1      default: []
[11] confirm_url                                    VARCHAR(256)         null: true   primary: false  isArray: false  auto: false  col: VARCHAR         len: 256     default: []
[12] biz_apply_no                                   VARCHAR(32)          null: true   primary: false  isArray: false  auto: false  col: VARCHAR         len: 32      default: []
[13] emp_id                                         VARCHAR(16)          null: true   primary: false  isArray: false  auto: false  col: VARCHAR         len: 16      default: []
[14] create_time                                    TIMESTAMPTZ          null: false  primary: false  isArray: false  auto: false  col: TIMESTAMPTZ     len: -1      default: []
[15] update_time                                    TIMESTAMPTZ          null: false  primary: false  isArray: false  auto: false  col: TIMESTAMPTZ     len: -1      default: []


JSON Sample
-------------------------------------
{    "id": 36,    "apply_no": "cgeLPMTKLNmfpoiSunUqSbGqW",    "brand_id": "rkWDmiTTuLMNajTvyPRxXoIqT",    "alipay_account": "NkaOYWBufXeHnLvhQDJIpShYQ",    "contact_info": "eyNTdpKlOYREIxAjDfxchCFJh",    "batch_no": "jUvCFKtyyfCCxTLmVoNySeYcP",    "sign_info": "xQNeQCDKrXnMGDyuPnFyOBHfy",    "sign_type": "LyqKJyEaYTFDafbmElhALLKcJ",    "apply_state": "UjPwgQIlvVxkDofoVOIXOsLJr",    "apply_state_desc": "wMVUSiQhxDuMFkedYvNHNiYZo",    "audit_detail": "FgFVyhnsqwjpmoBKrgNKCJVXr",    "confirm_url": "aiylgRcUfuBHJYjmePvvuGHCI",    "biz_apply_no": "UglufhJGAyPXZvummEkYwVRss",    "emp_id": "qPVMVcCvslatYwbxwClLGMOWP",    "create_time": "2176-07-11T13:34:17.936936792+08:00",    "update_time": "2074-05-29T11:03:30.085973573+08:00"}



*/

// AlipayAgentSign struct is a row record of the alipay_agent_sign table in the wxpay database
type AlipayAgentSign struct {
	//[ 0] id                                             INT8                 null: false  primary: true   isArray: false  auto: false  col: INT8            len: -1      default: []
	ID int64 `gorm:"primary_key;column:id;type:INT8;"`
	//[ 1] apply_no                                       VARCHAR(32)          null: false  primary: false  isArray: false  auto: false  col: VARCHAR         len: 32      default: []
	ApplyNo string `gorm:"column:apply_no;type:VARCHAR;size:32;"`
	//[ 2] brand_id                                       VARCHAR(16)          null: false  primary: false  isArray: false  auto: false  col: VARCHAR         len: 16      default: []
	BrandID string `gorm:"column:brand_id;type:VARCHAR;size:16;"`
	//[ 3] alipay_account                                 VARCHAR(32)          null: false  primary: false  isArray: false  auto: false  col: VARCHAR         len: 32      default: []
	AlipayAccount string `gorm:"column:alipay_account;type:VARCHAR;size:32;"`
	//[ 4] contact_info                                   JSONB                null: false  primary: false  isArray: false  auto: false  col: JSONB           len: -1      default: []
	ContactInfo datatypes.JSON `gorm:"column:contact_info;type:JSONB;"`
	//[ 5] batch_no                                       VARCHAR(32)          null: false  primary: false  isArray: false  auto: false  col: VARCHAR         len: 32      default: []
	BatchNo string `gorm:"column:batch_no;type:VARCHAR;size:32;"`
	//[ 6] sign_info                                      JSONB                null: false  primary: false  isArray: false  auto: false  col: JSONB           len: -1      default: []
	SignInfo datatypes.JSON `gorm:"column:sign_info;type:JSONB;"`
	//[ 7] sign_type                                      VARCHAR(16)          null: false  primary: false  isArray: false  auto: false  col: VARCHAR         len: 16      default: []
	SignType string `gorm:"column:sign_type;type:VARCHAR;size:16;"`
	//[ 8] apply_state                                    VARCHAR(32)          null: true   primary: false  isArray: false  auto: false  col: VARCHAR         len: 32      default: []
	ApplyState sql.NullString `gorm:"column:apply_state;type:VARCHAR;size:32;"`
	//[ 9] apply_state_desc                               VARCHAR(64)          null: true   primary: false  isArray: false  auto: false  col: VARCHAR         len: 64      default: []
	ApplyStateDesc sql.NullString `gorm:"column:apply_state_desc;type:VARCHAR;size:64;"`
	//[10] audit_detail                                   JSONB                null: true   primary: false  isArray: false  auto: false  col: JSONB           len: -1      default: []
	AuditDetail datatypes.JSON `gorm:"column:audit_detail;type:JSONB;"`
	//[11] confirm_url                                    VARCHAR(256)         null: true   primary: false  isArray: false  auto: false  col: VARCHAR         len: 256     default: []
	ConfirmURL sql.NullString `gorm:"column:confirm_url;type:VARCHAR;size:256;"`
	//[12] biz_apply_no                                   VARCHAR(32)          null: true   primary: false  isArray: false  auto: false  col: VARCHAR         len: 32      default: []
	BizApplyNo sql.NullString `gorm:"column:biz_apply_no;type:VARCHAR;size:32;"`
	//[13] emp_id                                         VARCHAR(16)          null: true   primary: false  isArray: false  auto: false  col: VARCHAR         len: 16      default: []
	EmpID sql.NullString `gorm:"column:emp_id;type:VARCHAR;size:16;"`
	//[14] create_time                                    TIMESTAMPTZ          null: false  primary: false  isArray: false  auto: false  col: TIMESTAMPTZ     len: -1      default: []
	CreateTime time.Time `gorm:"column:create_time;type:TIMESTAMPTZ;"`
	//[15] update_time                                    TIMESTAMPTZ          null: false  primary: false  isArray: false  auto: false  col: TIMESTAMPTZ     len: -1      default: []
	UpdateTime time.Time `gorm:"column:update_time;type:TIMESTAMPTZ;"`
	//[16] alipay_account                                 VARCHAR(32)          null: false  primary: false  isArray: false  auto: false  col: VARCHAR         len: 32      default: []
	AppId string `gorm:"column:app_id;type:VARCHAR;size:32;"`
}

// TableName sets the insert table name for this struct type
func (a *AlipayAgentSign) TableName() string {
	return "alipay_agent_sign"
}

// BeforeSave invoked before saving, return an error if field is not populated.
func (a *AlipayAgentSign) BeforeSave() error {
	return nil
}

// Prepare invoked before saving, can be used to populate fields etc.
func (a *AlipayAgentSign) Prepare() {
}

// Validate invoked before performing action, return an error if field is not populated.
func (a *AlipayAgentSign) Validate() error {
	sInfo := &AliFaceToFaceSignInfo{}
	sInfo.ToStruct(a.SignInfo)
	if err := sInfo.validate(); err != nil {
		return err
	}
	cInfo := &AliSignContactInfo{}
	cInfo.ToStruct(a.ContactInfo)
	return cInfo.validate()
}

func (a *AlipayAgentSign) IsFinalState() bool {
	switch a.ApplyState.String {
	case "MERCHANT_CONFIRM_SUCCESS", "MERCHANT_APPLY_ORDER_CANCELED":
		return true
	case "MERCHANT_INFO_HOLD", "MERCHANT_CONFIRM_TIME_OUT":
		return true
	default:
		return false
	}
}

func (a *AlipayAgentSign) IsNewState(state string) bool {
	return a.ApplyState.String != state
}

func (a *AlipayAgentSign) UpdateAuditState(audit *AliSignAuditDetail) {
	a.ApplyState = util.AdaptNullString(audit.OrderStatus)
	switch a.ApplyState.String {
	case "MERCHANT_INFO_HOLD":
		a.ApplyStateDesc = util.AdaptNullString("暂存，提交事务出现业务校验异常")
	case "MERCHANT_AUDITING":
		a.ApplyStateDesc = util.AdaptNullString("审核中")
	case "MERCHANT_CONFIRM":
		a.ApplyStateDesc = util.AdaptNullString("待商户确认")
	case "MERCHANT_CONFIRM_SUCCESS":
		a.ApplyStateDesc = util.AdaptNullString("商户确认成功")
	case "MERCHANT_CONFIRM_TIME_OUT":
		a.ApplyStateDesc = util.AdaptNullString("商户超时未确认")
	case "MERCHANT_APPLY_ORDER_CANCELED":
		a.ApplyStateDesc = util.AdaptNullString("审核失败或商户拒绝")
	default:
		a.ApplyStateDesc = util.AdaptNullString("")
	}
	a.ConfirmURL = util.AdaptNullString(audit.ConfirmUrl)
	a.AuditDetail = audit.ToJson()
}

type AliFaceToFaceSignInfo struct {
	BatchNo                string `json:"batch_no"`                      // 事务编号, 忽略
	MccCode                string `json:"mcc_code"`                      // 经营类目编码
	SpecialLicensePic      string `json:"special_license_pic,omitempty"` // 特殊资质图片地址
	Rate                   string `json:"rate"`                          // 服务费率 （%）
	SignAndAuth            bool   `json:"sign_and_auth"`
	BusinessLicenseNo      string `json:"business_license_no"`                 // 营业执照号码
	BusinessLicensePic     string `json:"business_license_pic,omitempty"`      // 营业执照图片地址
	BusinessLicenseAuthPic string `json:"business_license_auth_pic,omitempty"` // 营业执照授权函图片地址
	LongTerm               bool   `json:"long_term"`                           // 是否长期有效
	DateLimitation         string `json:"date_limitation"`                     // 营业期限
	ShopScenePic           string `json:"shop_scene_pic,omitempty"`            // 店铺内景图片地址
	ShopSignBoardPic       string `json:"shop_sign_board_pic,omitempty"`       // 店铺门头照片地址
}

func (a *AliFaceToFaceSignInfo) ToStruct(r datatypes.JSON) {
	b, _ := r.MarshalJSON()
	_ = json.Unmarshal(b, a)
}

// 签约内容详情
func (a *AliFaceToFaceSignInfo) ToJson() datatypes.JSON {
	b, _ := json.Marshal(a)
	return b
}

// 用于提交给支付宝的 json 序列化
func (a *AliFaceToFaceSignInfo) ToJsonV2() []byte {
	b, _ := json.Marshal(a)
	return b
}

func (a *AliFaceToFaceSignInfo) validate() error {
	if a.MccCode == "" {
		return fmt.Errorf("商家经营类目编码必填")
	}
	if a.SignAndAuth && a.Rate == "" {
		return fmt.Errorf("当签约且授权时，服务费率必填")
	}
	return nil
}

// 签约联系人信息
type AliSignContactInfo struct {
	ContactName   string `json:"contact_name"`
	ContactMobile string `json:"contact_mobile"`
	ContactEmail  string `json:"contact_email"`
}

func (a *AliSignContactInfo) ToStruct(t datatypes.JSON) {
	b, _ := t.MarshalJSON()
	_ = json.Unmarshal(b, a)
}

func (a *AliSignContactInfo) ToJson() datatypes.JSON {
	b, _ := json.Marshal(a)
	return b
}

func (a *AliSignContactInfo) validate() error {
	if a.ContactName == "" || a.ContactMobile == "" || a.ContactEmail == "" {
		return fmt.Errorf("商家联系人名称，手机号，邮箱必填")
	}
	return nil
}

// AliSignAuditDetail 审核详情
type AliSignAuditDetail struct {
	OrderStatus  string `json:"order_status"` //  忽略
	ConfirmUrl   string `json:"confirm_url"`  //  忽略
	AgentAppID   string `json:"agent_app_id"`
	RejectReason string `json:"reject_reason"`
	MerchantPID  string `json:"merchant_pid"`
}

func (a *AliSignAuditDetail) ToStruct(t datatypes.JSON) {
	b, _ := t.MarshalJSON()
	_ = json.Unmarshal(b, a)
}

func (a *AliSignAuditDetail) ToJson() datatypes.JSON {
	b, _ := json.Marshal(a)
	return b
}
